package efu.nf.like.service.impl;



import com.fasterxml.jackson.databind.ObjectMapper;
import efu.nf.like.common.config.RabbitConfig;
import efu.nf.like.common.confirm.ConfirmCallbackService;
import efu.nf.like.common.confirm.RabbitManager;
import efu.nf.like.common.enumeration.RedisKeyEnum;
import efu.nf.like.mapper.LikeMapper;
import efu.nf.like.model.dto.LikeDTO;
import efu.nf.like.model.entity.Like;
import efu.nf.like.service.LikeService;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.amqp.core.Message;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.io.IOException;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * @author lwj
 * @create 2025-10-12-16:58
 */
@Service
@Slf4j
@RequiredArgsConstructor
@Transactional
public class LikeServiceImpl implements LikeService, ConfirmCallbackService {
    private final LikeMapper likeMapper;
    private final RedisTemplate<String, Integer> redisTemplate;
    private final RabbitManager manager;

    /**
     * 过期时间
     */
    private final Long TIMEOUT = 30000L;
    private Integer count = 2;

    @Override
    public LikeDTO like(Integer postId, Integer userId) {
        boolean userLikeStatus = false;
        // 点赞键
        String likeKey = RedisKeyEnum.POST_LIKE_PREFIX.getValue() + postId;
        // 判断当前用户是否点赞了
        if(isLike(postId, userId)){
            // 点赞了，从缓存中移除
            redisTemplate.opsForSet().remove(likeKey, userId);
        }else{
            userLikeStatus = true;
            // 添加缓存
            cacheLike(likeKey, userId);
        }
        // 构建 LikeDTO
        LikeDTO likeDTO = new LikeDTO(userLikeStatus, postId, userId,likeCount(postId));
        // 发送消息到消息队列
        manager.send(RabbitConfig.EXCHANGE_NAME, RabbitConfig.ROUTING_KEY, "likeServiceImpl", likeDTO);
        return likeDTO;
    }

    @Override
    public boolean isLike(Integer postId, Integer userId) {
        // 点赞键
        String likeKey = RedisKeyEnum.POST_LIKE_PREFIX.getValue() + postId;
        // 判断是否有用户进行点赞操作
        if(!redisTemplate.hasKey(likeKey)){
            // 不存在,从数据库中获取点赞信息
            List<Like> likes = likeMapper.selectByPostId(postId);
            likes.forEach(like -> {
                // 缓存点赞信息
                cacheLike(likeKey, like.getUserId());
            });
        }
        // 判断当前用户是否点赞
        return redisTemplate.opsForSet().isMember(likeKey, userId);
    }

    @Override
    public Long likeCount(Integer postId) {
        // 使用 Redis 中 Set 的 SCARD 方法获取点赞数
        return redisTemplate.opsForSet().size(RedisKeyEnum.POST_LIKE_PREFIX.getValue() + postId);
    }

    /**
     * 投递失败后的回调处理
     * @param message 投递的消息对象
     */
    @Override
    public void confirmCallback(Message message) {
        try {
            // 反序列化为 LikeDTO
            LikeDTO likeDTO = new ObjectMapper().readValue(message.getBody(), LikeDTO.class);
            // 缓存键
            String postKey = RedisKeyEnum.POST_LIKE_PREFIX.getValue() + likeDTO.getPostId();
            // 判断用户点赞状态,反向操作
            if (likeDTO.isUserLikeStatus()){
                // 从缓存中删除
                redisTemplate.opsForSet().remove(postKey, likeDTO.getUserId());
            }else{
                // 添加到缓存中
                redisTemplate.opsForSet().add(postKey, likeDTO.getUserId());
            }
        } catch (IOException e) {
            log.error("反序列化对象失败：{}", e.getMessage());
            throw new RuntimeException(e);
        }
    }

    /**
     * 缓存点赞信息
     * @param likeKey 点赞键
     * @param userId  用户编号
     */
    private void cacheLike(String likeKey, Integer userId){
        // 添加到缓存中
        redisTemplate.opsForSet().add(likeKey, userId);
        // 设置过期时间
        redisTemplate.expire(likeKey,TIMEOUT, TimeUnit.SECONDS);
    }
}
